<template>
  <div class="z-crud-wrapper">
    <p>
      <a-button v-if="option.addBtn" @click="handleAdd">
        <template #icon>
          <PlusOutlined />
        </template>
        新增
      </a-button>

      <slot name="menu"></slot>
    </p>
    <a-form :model="searchState" layout="inline" ref="formRef">
      <a-row :gutter="[0, 0]">
        <template v-for="(item, index) in columns">
          <a-col v-if="item.search" :key="index" :span="item.searchSpan || 24">
            <a-form-item :label="item.title" :rules="item.rules" :name="item.dataIndex">
              <component
                v-if="item.type !== 'select'"
                :is="'a-' + (item.type || 'input')"
                show-time
                valueFormat="YYYY-MM-DD HH:mm:ss"
                v-model:value="item.searchValue"
                v-model:checked="item.searchValue"
                :placeholder="item.placeholder || '请输入' + item.title"
              ></component>
              <a-select
                v-else
                v-model:value="item.searchValue"
                :placeholder="'请输入' + item.title"
              >
                <a-select-option
                  :value="data.value"
                  v-for="(data, index) in item.dicData"
                  :key="index"
                  :disabled="data.disabled"
                  >{{ data.label }}</a-select-option
                >
              </a-select>
            </a-form-item>
          </a-col>
        </template>
      </a-row>
    </a-form>
    <a-spin :spinning="tableLoading" tip="Loading...">
      <p class="z-crud-nav">
        <span class="z-curd-selection">
          <a-alert
            :message="`当前已选中 ${selectedRowKeys.length} 项`"
            banner
            v-if="option.selection"
            style="width: 50%; margin-bottom: 10px"
          />
        </span>

        <a-tooltip v-if="option.refreshBtn">
          <template #title>刷新</template>
          <span class="refresh-icon-box" @click="handleRefresh">
            <RedoOutlined class="refresh-icon" />
          </span>
        </a-tooltip>
      </p>
      <a-table
        :dataSource="data"
        :columns="headerColumns"
        :bordered="option.bordered"
        :tableLayout="option.tableLayout"
        :title="option.title"
        :rowKey="record => record.id"
        :row-selection="
          option.selection
            ? {
                selectedRowKeys: selectedRowKeys,
                onChange: onSelectChange,
              }
            : null
        "
        :pagination="false"
      >
        <template v-slot:[item.slots?.customRender]="{ record }" v-for="(item, index) in columns">
          <slot :name="item.slots.customRender" :record="record" :key="index">
            <a-button
              size="small"
              style="margin-right: 10px"
              v-if="option.viewBtn"
              @click="handleView(record)"
            >
              <template #icon>
                <ZoomInOutlined />
              </template>
              查看
            </a-button>
            <a-button
              size="small"
              type="primary"
              style="margin-right: 10px"
              v-if="option.editBtn"
              @click="handleEdit(record)"
            >
              <template #icon>
                <FormOutlined />
              </template>
              编辑
            </a-button>
            <a-button
              size="small"
              type="danger"
              style="margin-right: 10px"
              v-if="option.delBtn"
              @click="handleDel(record)"
            >
              <template #icon>
                <DeleteOutlined />
              </template>
              删除
            </a-button>
            <slot name="menuLeft" :record="record"></slot>
          </slot>
        </template>
      </a-table>

      <div v-if="page" class="page-wrapper">
        <a-pagination
          v-model:current="page.currentPage"
          :total="page.total"
          show-less-items
          show-size-changer
          :page-size="page.pageSize"
          @showSizeChange="onShowSizeChange"
        >
          <template #buildOptionText="props">
            <span v-if="props.value !== page.total">{{ props.value }}条/页</span>
            <span v-else>全部</span>
          </template>
        </a-pagination>
        <span>共{{ page.total }}条记录</span>
      </div>
    </a-spin>

    <a-modal
      v-model:visible="visible"
      :title="hasEdit ? '编辑' : '新增'"
      @ok="handleSubmit()"
      :maskClosable="false"
      :okText="hasEdit ? '保存' : '提交'"
      cancelText="取消"
      :confirm-loading="okLoading"
      :width="option.modalWidth || 520"
      centered
      :afterClose="() => (formState = {})"
    >
      <a-form :model="formState" ref="formRef">
        <a-row :gutter="[0, 0]">
          <template v-for="(item, index) in columns">
            <a-col
              v-if="item.slots?.customRender !== 'operation' && item.display"
              :key="index"
              :span="24"
            >
              <a-form-item
                :label="item.title"
                :rules="item.rules"
                :name="item.dataIndex"
                :labelCol="{ span: option.labelSpan || 0 }"
                :wrapperCol="{ span: item.span ? item.span : 24 - (option.labelSpan || 0) }"
              >
                <template v-if="item.formSlot">
                  <slot :name="item.dataIndex + 'Form'" :record="formState"></slot>
                </template>
                <template v-else>
                  <tiny
                    v-if="item.type === 'richText'"
                    :width="'100%'"
                    v-model:myValue="formState[item.dataIndex]"
                    :height="item.height || 400"
                    :url="'图片路径'"
                    ref="tinymce"
                    :slotStyle="{
                      display: 'flex',
                      justifyContent: 'center',
                      padding: '10px 0 0',
                    }"
                  ></tiny>

                  <component
                    v-if="item.type !== 'select'"
                    :is="'a-' + (item.type || 'input')"
                    show-time
                    valueFormat="YYYY-MM-DD HH:mm:ss"
                    v-model:value="formState[item.dataIndex]"
                    v-model:checked="formState[item.dataIndex]"
                    :tree-data="item.treeData"
                    :replaceFields="item.replaceFields"
                    show-search
                    @icon-change="iconChange"
                    :defaultValue="formState[item.dataIndex]"
                    :load-data="item['loadTreeData']"
                    :placeholder="item.placeholder || '请输入' + item.title"
                  >
                    <template #iconContent>
                      <div>
                        <a-tag style="cursor: pointer" size="large">{{
                          formState[item.dataIndex] || '请选择图标'
                        }}</a-tag>
                      </div>
                    </template>
                  </component>
                  <a-select
                    v-else
                    v-model:value="formState[item.dataIndex]"
                    :placeholder="'请选择' + item.title"
                  >
                    <a-select-option
                      :value="data.value"
                      v-for="(data, index) in item.dicData"
                      :key="index"
                      :disabled="data.disabled"
                      >{{ data.label }}</a-select-option
                    >
                  </a-select>
                </template>
              </a-form-item>
            </a-col>
          </template>
        </a-row>
      </a-form>
    </a-modal>

    <!-- 查看 -->
    <a-modal
      v-model:visible="isView"
      title="查看"
      :footer="null"
      :width="option.modalWidth || 520"
      centered
    >
      <a-form>
        <a-row :gutter="[0, 0]">
          <template v-for="(item, index) in columns">
            <a-col
              v-if="item.slots?.customRender !== 'operation' && item.display"
              :key="index"
              :span="24"
            >
              <a-form-item
                :label="item.title"
                :name="item.dataIndex"
                :labelCol="{ span: option.labelSpan || 0 }"
                :wrapperCol="{ span: item.span ? item.span : 24 - (option.labelSpan || 0) }"
                style="color:#999"
              >
                <template v-if="item.viewFormSlot">
                  <slot :name="item.dataIndex + 'ViewForm'" :record="formState"></slot>
                </template>
                <template v-else>
                  <div v-if="item.type === 'richText'">
                    <div v-html="formState[item.dataIndex]"></div>
                  </div>

                  <div v-else style="font-weight:600;color:#666">
                    {{ formState[item.dataIndex] }}
                  </div>
                </template>
              </a-form-item>
            </a-col>
          </template>
        </a-row>
      </a-form>
    </a-modal>
  </div>
</template>

<script lang="ts">
import {
  PropType,
  defineComponent,
  onMounted,
  reactive,
  ref,
  toRefs,
  watch,
  computed,
  toRaw,
  nextTick,
  createVNode,
} from 'vue';

//TODO
import {
  PlusOutlined,
  ZoomInOutlined,
  FormOutlined,
  RedoOutlined,
  DeleteOutlined,
  ExclamationCircleOutlined,
} from '@ant-design/icons-vue';
import { useForm } from '@ant-design-vue/use';
import { Modal } from 'ant-design-vue';
import aIconSelect from '../components/icon-select.vue';
// import Column from "ant-design-vue/lib/table/Column";
import tiny from '@/components/tiny.vue';
type Key = string | number;

type State = {
  selectedRowKeys: Key[];
  visible: boolean;
  formState: any;
  hasEdit: boolean;
  okLoading: boolean;
  searchState: any;
  isView: boolean;
};

export default defineComponent({
  name: 'z-curd',
  components: {
    PlusOutlined,
    ZoomInOutlined,
    FormOutlined,
    DeleteOutlined,
    RedoOutlined,
    tiny,
    ExclamationCircleOutlined,
    aIconSelect,
  },
  props: {
    tableLoading: {
      type: Boolean,
      default: () => false,
    },
    page: {
      type: Object,
      default: null,
    },
    data: {
      type: Array as PropType<any[]>,
      dafault: () => [],
    },
    option: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  setup(props, context) {
    const state = reactive<State>({
      selectedRowKeys: [],
      visible: false,
      formState: {},
      hasEdit: false,
      okLoading: false,
      searchState: {},
      isView: false,
    });

    const onShowSizeChange = (current: number, pageSize: number) => {
      props.page.pageSize = pageSize;
      context.emit('on-load', props.page);
    };
    const tinymce = ref<any>(null);
    const richValue = ref<string>('');
    const columns = computed(() => props.option.column);
    const formRef = ref();
    const headerColumns = computed(() => columns.value.filter(item => !item.hide));
    onMounted(() => {
      const { align } = props.option;
      for (const [index, filed] of columns.value.entries()) {
        filed.display = filed.hasOwnProperty('display') ? filed.display : true;
        filed.hide = filed.hasOwnProperty('hide') ? filed.hide : false;
        filed.align = align ? filed.align : 'center';
        if (filed.slot) {
          filed.slots = { customRender: filed.dataIndex };
        }
      }
      if (props.option.operation) {
        if (columns.value[columns.value.length - 1].slots?.customRender === 'operation') {
          return;
        }

        columns.value.splice(columns.value.length, 1, {
          title: props.option.operationTitle || '操作',
          align: 'center',
          slots: { customRender: 'operation' },
        });
      }
      context.emit('on-load', props.page);
    });
    const handleEdit = rec => {
      state.okLoading = false;
      state.hasEdit = true;
      state.visible = true;
      state.formState = rec;
      nextTick(() => {
        try {
          formRef.value.clearValidate();
        } catch (error) {}
      });
    };
    const handleView = rec => {
      state.isView = true;
      state.formState = rec;
    };
    if (props.page) {
      watch(
        () => props.page.currentPage,
        v => {
          context.emit('on-load', props.page);
        }
      );
    }
    const onSelectChange = (selectedRowKeys: Key[]) => {
      const hasData = props.data.filter((it: any) => selectedRowKeys.includes(it.id));
      context.emit(
        'on-selection',
        hasData.map(item => toRaw(item))
      );
      state.selectedRowKeys = selectedRowKeys;
    };
    //图标事件回传
    const iconChange = (val: string) => {
      const iconRow = columns.value.find(item => item.type === 'iconSelect');
      toRaw(state.formState)[iconRow.dataIndex] = val;
    };
    const handleRefresh = () => {
      if (props.page) {
        props.page.currentPage = 1;
      }
      context.emit('on-load', props.page);
    };

    const handleAdd = () => {
      state.okLoading = false;
      state.hasEdit = false;
      state.visible = true;
      state.formState = {};
      nextTick(() => {
        try {
          formRef.value.clearValidate();
          tinymce.value.clearRichValue();
        } catch (error) {}
      });
    };

    const handleSubmit = () => {
      formRef.value.validate().then(() => {
        const res = {};
        const displayData = columns.value.filter(
          item => item.display && item.slots?.customRender !== 'operation'
        );
        const isRichText = columns.value.filter(item => item.type === 'richText');

        for (const item of displayData) {
          res[item.dataIndex] = state.formState[item.dataIndex];
        }
        if (isRichText.length) {
          isRichText.forEach(item => {
            res[item.dataIndex] = tinymce.value.getRichValue();
          });
        }

        if (state.hasEdit) {
          res['id'] = state.formState['id'];
        }
        state.okLoading = true;
        context.emit(state.hasEdit ? 'on-update' : 'on-save', res, () => {
          state.okLoading = false;
          state.visible = false;
        });
      });
    };

    const handleDel = record => {
      Modal.confirm({
        content: '确定删除该条数据吗?',
        icon: createVNode(ExclamationCircleOutlined),
        okText: '确定',
        onOk() {
          state.okLoading = true;
          context.emit('on-del', record, () => {
            state.okLoading = false;
            state.visible = false;
          });
        },
        cancelText: '再考虑一下',
        onCancel() {
          Modal.destroyAll();
        },
      });
    };

    const handleOk = () => {};
    return {
      onShowSizeChange,
      handleView,
      formRef,
      ...toRefs(state),
      onSelectChange,
      handleRefresh,
      handleEdit,
      handleOk,
      columns,
      handleAdd,
      handleSubmit,
      headerColumns,
      tinymce,
      richValue,
      handleDel,
      iconChange,
    };
  },
});
</script>

<style lang="less" scoped>
.page-wrapper {
  display: flex;
  align-items: center;
  margin-top: 30px;

  > span {
    margin-left: 3px;
    color: #999;
  }
}
.z-crud-nav {
  display: flex;
  justify-content: flex-end;
  .z-curd-selection {
    flex: auto;
  }
  .refresh-icon-box {
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    background: #fff;
    border: 1px solid #dcdfe6;
    color: #606266;
    -webkit-appearance: none;
    text-align: center;
    transition: 0.1s;
    font-weight: 500;
    border-radius: 50%;
    width: 35px;
    height: 35px;
    display: flex;
    justify-content: center;
    align-items: center;
    &:hover {
      background: #f3f1f1;
    }
  }
}
</style>